﻿using System.Diagnostics;

namespace System.NETool;

/// <summary>
/// 提供扩展方法以简化进程的启动和输出捕获。
/// </summary>
public static class ProcessEx
{
    /// <summary>
    /// 同步运行进程并返回输出。
    /// </summary>
    /// <param name="cmd">要执行的命令。</param>
    /// <returns>命令的输出结果。</returns>
    public static string RunProcessWithOutput(string cmd)
    {
        using var process = new Process();
        return process.RunWithOutput(cmd);
    }

    /// <summary>
    /// 扩展方法，同步运行进程并返回输出。
    /// </summary>
    /// <param name="this">进程实例。</param>
    /// <param name="cmd">要执行的命令。</param>
    /// <returns>命令的输出结果。</returns>
    public static string RunWithOutput(this Process @this, string cmd)
    {
        try
        {
            // 设置要启动的应用程序
            @this.StartInfo.FileName = "bash";
            // 是否使用操作系统shell启动
            @this.StartInfo.UseShellExecute = false;
            // 接受来自调用程序的输入信息
            @this.StartInfo.RedirectStandardInput = true;
            // 输出信息
            @this.StartInfo.RedirectStandardOutput = true;
            // 输出错误
            @this.StartInfo.RedirectStandardError = false;
            // 不显示程序窗口
            @this.StartInfo.CreateNoWindow = true;
            @this.Start();
            @this.StandardInput.WriteLine(cmd);
            @this.StandardInput.Close();
            var fileData = @this.StandardOutput.ReadToEnd();
            @this.WaitForExit();
            return fileData;
        }
        catch (Exception ex)
        {
            return cmd + '\n' + "Ex: " + ex.Message;
        }
        finally
        {
            @this.Close();
        }
    }

    /// <summary>
    /// 异步运行进程并返回输出。
    /// </summary>
    /// <param name="cmd">要执行的命令。</param>
    /// <returns>命令的输出结果。</returns>
    public static async Task<string> RunProcessWithOutputAsync(string cmd)
    {
        using var process = new Process();
        return await process.RunWithOutputAsync(cmd);
    }

    /// <summary>
    /// 扩展方法，异步运行进程并返回输出。
    /// </summary>
    /// <param name="this">进程实例。</param>
    /// <param name="cmd">要执行的命令。</param>
    /// <returns>命令的输出结果。</returns>
    public static async Task<string> RunWithOutputAsync(this Process @this, string cmd)
    {
        try
        {
            // 设置要启动的应用程序
            @this.StartInfo.FileName = "bash";
            // 是否使用操作系统shell启动
            @this.StartInfo.UseShellExecute = false;
            // 接受来自调用程序的输入信息
            @this.StartInfo.RedirectStandardInput = true;
            // 输出信息
            @this.StartInfo.RedirectStandardOutput = true;
            // 输出错误
            @this.StartInfo.RedirectStandardError = false;
            // 不显示程序窗口
            @this.StartInfo.CreateNoWindow = true;
            @this.Start();
            await @this.StandardInput.WriteLineAsync(cmd);
            @this.StandardInput.Close();
            var fileData = await @this.StandardOutput.ReadToEndAsync();
            await @this.WaitForExitAsync();
            return fileData;
        }
        catch (Exception ex)
        {
            return cmd + '\n' + "Ex: " + ex.Message;
        }
        finally
        {
            @this.Close();
        }
    }

    /// <summary>
    /// 同步运行进程。
    /// </summary>
    /// <param name="cmd">要执行的命令。</param>
    /// <param name="args">命令参数。</param>
    public static void RunProcess(string cmd, string args = "")
    {
        using var process = new Process();
        process.Run(cmd, args);
    }

    /// <summary>
    /// 扩展方法，同步运行进程。
    /// </summary>
    /// <param name="this">进程实例。</param>
    /// <param name="cmd">要执行的命令。</param>
    /// <param name="args">命令参数。</param>
    public static void Run(this Process @this, string cmd, string args = "")
    {
        try
        {
            @this.StartInfo.FileName = cmd;
            @this.StartInfo.Arguments = args;
            @this.Start();
            @this.WaitForExit();
        }
        catch (Exception ex)
        {
            Console.WriteLine(cmd + ": " + args + '\n' + "Ex: " + ex.Message);
        }
        finally
        {
            @this.Close();
        }
    }

    /// <summary>
    /// 异步运行进程。
    /// </summary>
    /// <param name="cmd">要执行的命令。</param>
    /// <param name="args">命令参数。</param>
    public static async Task RunProcessAsync(string cmd, string args = "")
    {
        using var process = new Process();
        await process.RunAsync(cmd, args);
    }

    /// <summary>
    /// 扩展方法，异步运行进程。
    /// </summary>
    /// <param name="this">进程实例。</param>
    /// <param name="cmd">要执行的命令。</param>
    /// <param name="args">命令参数。</param>
    public static async Task RunAsync(this Process @this, string cmd, string args = "")
    {
        try
        {
            @this.StartInfo.FileName = cmd;
            @this.StartInfo.Arguments = args;
            @this.Start();
            await @this.WaitForExitAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine(cmd + ": " + args + '\n' + "Ex: " + ex.Message);
        }
        finally
        {
            @this.Close();
        }
    }
}
